﻿package igz.fleaxy.pattern
{
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	import flash.utils.getQualifiedSuperclassName;
	import igz.fleaxy.util.Convert;
	import igz.fleaxy.util.DataTableUtil;
	import igz.fleaxy.util.DateTimeUtil;
	import igz.fleaxy.util.ObjectUtil;

	/**
	 *  Esta clase implementa la estructura de DTO utilizada en Inteligenz.
	 * En este  caso es un DTO inteligente ya que él mismo se ocupa de auto-importarse desde JSON y XML, entre otras cosas.
	 * 
	 * 
	 * @author Intelygenz | www.intelygenz.com
	 */
	public class Dto extends Object {

		/**
		 * Devuelve el nombre de la clase
		 */
		protected function get _ClassName () : String {
			var className:String = getQualifiedClassName( this );
			return className.substring( className.indexOf("::") + 2 );
		}

		/**
		 * Return the name of class including full package path
		 */
		protected function get _FullClassName () : String {
			return getQualifiedClassName( this );
		}

		public function Dto( p_abstractFactory:Object=null ) {
		}

		/**
		 *   Método de carga a partir del cual se rellenan los datos del DTO
		 * 
		 * @param p_xml: xml (subconjunto del XML) que mantiene todos los datos necesarios para este dto
		 * 
		 * 
		 */
		internal function _LoadFromXML(p_xml:XML, p_dateTimeFormat:String = null) : void {
			var fieldName:String;
			var node:XML;
			for each ( node in p_xml.children() ) {
				fieldName = "$" + node.name();
				if ( this.hasOwnProperty( fieldName ) ) {
					if ( getQualifiedSuperclassName(this[fieldName]) == "igz.fleaxy.pattern::AbstractFactory" ) {
						var refClass : Class = getDefinitionByName(getQualifiedClassName(this[fieldName])) as Class;
						this[fieldName] = new refClass();
						if ( node.children().length() > 0 ) {
							(this[fieldName] as AbstractFactory).$LoadFromXML(node, node.children()[0].name());
						}
					}
					else {
						_LoadField(fieldName, node, p_dateTimeFormat);
					}
				}
			}
		}

		/**
		 *   Método de carga a partir del cual se rellenan los datos del JSON
		 * 
		 * @param p_dataTable: Todo el JSON
		 * @param p_index: índice donde se encuentran los datos de este DTO
		 */
		public function $LoadFromJSON(p_dataTable:Object, p_index:int, p_dateTimeFormat:String = null) : void {
			var publicFields : Array = p_dataTable[DataTableUtil.$COLUMNS_LABEL] as Array;
			var values : Array = (p_dataTable[DataTableUtil.$ROWS_LABEL] as Array)[p_index];
			var fieldName : String;
			for each( fieldName in publicFields ) {
				if ( this.hasOwnProperty(fieldName) ) {
					_LoadField(fieldName, values[ publicFields.indexOf(fieldName) ], p_dateTimeFormat);
				}
			}
		}

		/**
		 *   Carga un valor en un determinado campo
		 *
		*  @param p_fieldName: Nombre del campo a cargar
		*  @param p_value : Valor (puede ser de cualquier tipo)
		*  
		*  @example
		*            
		*
		 */
		private function _LoadField(p_fieldName:String, p_value:*, p_dateTimeFormat:String = null):void {
			switch ( ObjectUtil.$GetType(this, p_fieldName) ) {
				case "number":
					this[p_fieldName] = (p_value == "") ? NaN : p_value;
				break;
					
				case "date":
					this[p_fieldName] = DateTimeUtil.$ToDate(p_value, p_dateTimeFormat);
				break;
				
				case "boolean":
					this[p_fieldName] = Convert.$ToBoolean( p_value );
				break;
					
				default:
					this[p_fieldName] = p_value;
			}
		}

		/**
		 * 
		 * @return String Cadena de caracteres con los datos del DTO
		 * 
		 */
		public function $Debug():String{
			var varList:XMLList = flash.utils.describeType(this)..variable;
			var debug:String = "";
			for(var i:int; i < varList.length(); i++){
					debug += "\n" + varList[i].@name + " = " + this[varList[i].@name];
			}
			return debug;
		}
		
		/**
		 * Devuelve un objeto del tipo { "FieldName@Dto":FieldValue, ... }
		 * Útil para ser pasado como parámetros en llamadas a servidor.
		 * 
		 *
		 * 
		 * @return { "Field1@Example" : "value1
		 *			,"Field2@Example" : 2
		 *		}
		 *  
		 *
		 */
		public function get $NameValue () : Object {
			var nameValue : Object = new Object();

			var fieldList : XMLList = describeType(this).variable;
			var fieldName : String;
			var fieldValue : String;
			for each ( fieldName in fieldList.@name ) {
				fieldValue = Convert.$ToString( this[ fieldName ] ).replace(/^NaN$/, "");
				nameValue[ fieldName.replace(/^\$/, "") + "@" + _ClassName.replace(/Dto$/, "") ] = fieldValue;
			}

			return nameValue;
		}
		
	}
	
}